package dawn.ioc;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import dawn.core.dispatch.Invoker;
import dawn.net.RpcInvoker;

public class InvokerGenerator {

	public static Invoker<Object> build(Object ins, Method m) {

		RpcInvoker invoker = null;
		try {
			if ((ins.getClass().getModifiers() & Modifier.PUBLIC) != 1) {
				// error
				System.err.println("not public");
			}

			if ((m.getModifiers() & Modifier.PUBLIC) != 1) {
				// error
				System.err.println("not public");
			}

			ClassPool pool = ClassPool.getDefault();
			CtClass ct = pool.makeClass("create." + ins.getClass().getName() + m.getName());
			ct.addInterface(pool.get(RpcInvoker.class.getName()));// 实现IInvoker接口
			ct.setModifiers(Modifier.PUBLIC);

			// 构造方法
			CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, ct);
			ctConstructor.setBody(";");
			ct.addConstructor(ctConstructor);

			// 添加字段
			CtField filedObj = new CtField(pool.getCtClass(ins.getClass().getName()), "obj", ct);
			filedObj.setModifiers(Modifier.PUBLIC);
			ct.addField(filedObj);

			// 实现set方法
			StringBuilder setStr = new StringBuilder("public void set(Object o, java.lang.reflect.Method method){");
			setStr.append("this.obj = (" + ins.getClass().getName() + ")o;}");
			CtMethod setMethod = CtMethod.make(setStr.toString(), ct);
			ct.addMethod(setMethod);

			// 实现invoker方法
			StringBuilder invokerStr = new StringBuilder("public void handle(Event e) {");
			if (m.getReturnType() == Void.class) {
				invokerStr.append("obj." + m.getName() + "(e);");
				invokerStr.append("return null;}");
			} else {
				invokerStr.append("return obj." + m.getName() + "(e);}");
			}
			CtMethod invokeMethod = CtMethod.make(invokerStr.toString(), ct);
			invokeMethod.setModifiers(Modifier.PUBLIC);
			ct.addMethod(invokeMethod);

			invoker = (RpcInvoker) ct.toClass().newInstance();
			invoker.set(ins, m);
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (RuntimeException e) {
			e.printStackTrace();
		} catch (NotFoundException e) {
			e.printStackTrace();
		} catch (CannotCompileException e) {
			e.printStackTrace();
		}

		return invoker;
	}

	public static boolean hasAnnotation(Annotation[] array, Class<?> clz) {
		if (array == null)
			return false;

		// XXX 待验证，这么写可能不对
		for (Annotation annotation : array) {
			if (annotation.equals(clz))
				return true;
		}

		return false;
	}
}
